/**
 *  \file   xmac_rx.c
 *  \author Miora ANDRIAMANOHARISOA, Loic MINGHETTI
 *  \date   PFE 2011
 **/

#include "include.h"


// RX


uint8_t rx_buffer_msg[CONF_MAX_MSG_SIZE];
int     rx_buffer_rssi;
char    rx_buffer_flag;


// called on packet received 
void xmac_rx_cb(uint8_t* buffer, int size, int8_t rssi) {

	if (verbocity >= 2) {
		printf("\r\n        Received: RSSI=%d, size=%d, from=%u, msg=", rssi, size, *((unsigned int *) buffer));
		int i;
		for(i = 0; i < size ;i++ ){
			printf("%x ", buffer[i]);
		}
	}
	
	switch (size) {
	case 0:
		if (verbocity >= 2) printf("\r\nmsg size 0");
		break;
	case -EEMPTY:
		if (verbocity >= 2) printf("\r\nmsg empty");
		break;
	case -ERXFLOW:
		if (verbocity >= 2) printf("\r\nmsg rx overflow");
		break;
	case -ERXBADCRC:
		if (verbocity >= 2) printf("\r\nmsg rx bad CRC");
		break;
	case -ETXFLOW:
		if (verbocity >= 2) printf("\r\nmsg tx overflow");
		break;
	default:
		if (size > 0) {
			memcpy(rx_buffer_msg, buffer, size);
			rx_buffer_rssi = rssi;
			rx_buffer_flag = 1;
		} else {
			/* packet error, drop */
			if (verbocity >= 2) printf("\r\nmsg packet error size=%d\n",size);
		}
		break;
	}
	xmac_listen_stop();
	if (!rx_buffer_flag) xmac_listen_start();
}

void xmac_rx_init() {
	rx_buffer_flag = 0;	 
	cc2500_rx_register_buffer(rx_buffer_msg, CONF_MAX_MSG_SIZE);  
	cc2500_rx_register_cb(xmac_rx_cb);
}

void xmac_listen_start () {
	led_red_on();
	rx_buffer_flag = 0;
	cc2500_rx_enter();
}
void xmac_listen_stop () {
	led_red_off();
	cc2500_idle();
}


PT_THREAD(thread_xmac_rx(struct pt *pt)) {
    PT_BEGIN(pt);

    static msg_preambule * p_preambule;
    static msg_preambule_ack preambule_ack;
    static msg_data * p_data;
    static msg_data_ack data_ack;
    static int i;
    
    while(1) {
    	

		while (1) {
			TIMER_RX = 0; // received preambule timeout
			// listen for preambule or timeout
			xmac_listen_start();
			PT_WAIT_UNTIL(pt, TIMER_RX >= CONF_RX_DURATION || rx_buffer_flag);
			TIMER_RX = 0; // delay before sending ack
			if (rx_buffer_flag) {
				if (rx_buffer_msg[2] != MSG_TYPE_PREAMBULE) {
					if (verbocity) printf("\r\nRX : Received invalid message while expecting preambule");
					PT_RESTART(pt);
				}
				if (rx_buffer_rssi < CONF_RX_RSSI_THRESHOLD)  {
					if (verbocity) printf("\r\nRX : Received preambule but RSSI too low (%d<%d)", rx_buffer_rssi, CONF_RX_RSSI_THRESHOLD);
					PT_RESTART(pt);
				}
				p_preambule = (msg_preambule *) rx_buffer_msg;
				if ((*p_preambule).destination_hop_count < node_hop_count)  {
					if (verbocity) printf("\r\nRX : Received preambule with lower hop count");
					PT_RESTART(pt);
				}
				
				if (verbocity) printf("\r\nRX : Received valid preambule");
			
				// send preambule ack
				preambule_ack.source = node_id;
				preambule_ack.type = MSG_TYPE_PREAMBULE_ACK;
				preambule_ack.destination = (*p_preambule).source;
				preambule_ack.source_hop_count = node_hop_count;
				if (verbocity) printf("\r\nRX : Sending preambule ack msg");
			
				PT_WAIT_UNTIL(pt, TIMER_RX >= CONF_RADIO_SWITCH_DELAY); // give time for received to swtich tx->rx
				tx ((char *)&preambule_ack, MSG_SIZE_PREAMBULE_ACK);
				PT_YIELD(pt);
			
				// listen for data
				xmac_listen_start();
				TIMER_RX = 0; // data response timeout
				PT_WAIT_UNTIL(pt, TIMER_RX >= CONF_RESPONSE_TIMEOUT || rx_buffer_flag);
				TIMER_RX = 0; // send data ack delay
				if (!rx_buffer_flag) {
					xmac_listen_stop();
					if (verbocity) printf("\r\nRX : Timeout while expecting data");
					PT_RESTART(pt);
				} else if (rx_buffer_msg[2] != MSG_TYPE_DATA) { // if invalid msg received
					if (verbocity) printf("\r\nRX : Received invalid message while expecting data (wrong msg type %d)", rx_buffer_msg[2]);
					PT_RESTART(pt);
				}
				p_data = (msg_data *) rx_buffer_msg;
				if ((*p_data).destination != node_id) {
					if (verbocity) printf("\r\nRX : Received invalid message while expecting data (wrong destination)");
					PT_RESTART(pt);
				}
				if (verbocity) printf("\r\nRX : Received valid data");
	
				// send data ack
				data_ack.source = node_id;
				data_ack.type = MSG_TYPE_DATA_ACK;
				data_ack.destination = (*p_data).source;
				data_ack.packet_id = (*p_data).packet_id;
				if (verbocity) printf("\r\nRX : Sending data ack msg");
			
				PT_WAIT_UNTIL(pt, TIMER_RX >= CONF_RADIO_SWITCH_DELAY); // give time for received to swtich tx->rx
				tx ((char *)&data_ack, MSG_SIZE_DATA_ACK);
				PT_YIELD(pt);
			
				// process data
				
				for (i = 0; i < (*p_data).data_length/MSG_SIZE_DATA_TEMP; i++) {
					if (node_id == 0) {
						printf("\r\n**%u:%u:%d\r\n", (*p_data).data[i].source, (*p_data).data[i].packet_number, (*p_data).data[i].temp);
					} else {
						xmac_tx_append((*p_data).data[i]);
					}
				}
				
				TIMER_RX = 0;
				PT_WAIT_UNTIL(pt, TIMER_RX >= CONF_RADIO_SWITCH_DELAY); // give time for received to swtich tx->rx
			
			} else {
				xmac_listen_stop();
				if (verbocity) printf("\r\nRX : Channel is free");
				// channel is free, look for msg to tx
				if (tx_state == pending) {
					tx_state = active;
					PT_WAIT_UNTIL(pt, tx_state == inactive || tx_state == pending);
				}
				TIMER_RX = 0; // listen period
				PT_WAIT_UNTIL(pt, TIMER_RX >= CONF_RX_PERIOD || tx_state == pending);
			
			}
		}
    }

    PT_END(pt);
}

